const util = require('util');
const execSync = require('child_process').execSync
const { spawn } = require('child_process');
const fs = require('fs')
const path = require('path')

//change the node pwd
process.chdir(path.dirname(process.argv[1]));

//当前目录
const CWD_PATH = process.cwd();

//日志缓存
let LOG_DATA_CACHE = [0x11111111];

const INFO = msg => {
	if(DEBUG_FLAG){
		LOG_DATA_CACHE.push(msg)
		OUT_LOG();
	}
	console.log(msg)
}

const ERROR =  msg => {
	if(DEBUG_FLAG){
		LOG_DATA_CACHE.push("[ERROR:]"+msg)
		OUT_LOG();
	}
	console.log('\x1B[31m%s\x1B[0m', msg)
	throw msg;
}

const OUT_LOG = (forceWrite=false)=>{
	//not open debug pattern
	if(!DEBUG_FLAG)
		return;

	//init the log file
	if(LOG_DATA_CACHE[0]==0x11111111){
		LOG_DATA_CACHE = LOG_DATA_CACHE.slice(1,LOG_DATA_CACHE.length)
		fs.writeFileSync(LOG_FILE,"",{encoding:"utf-8"})
	}

	if(forceWrite || LOG_DATA_CACHE.length > 50){
		fs.appendFileSync(LOG_FILE,LOG_DATA_CACHE.join("\n"),{encoding:"utf-8"});
		LOG_DATA_CACHE = [];
	}

}


/**
	@Desc 同步运行系统命令 直到命令完全结束才返回数据
	@Param cmd:String 命令字符串 
	@Param printFlag:String 设置自动打印输出 默认：打印
*/
const SHELL = (cmd,isPrint=true)=>{

	//因为exec命令 会对 ' 符号进行一次转换
	if(cmd.trim().indexOf("opc") == 0 && cmd.indexOf(`'`) > -1)
		throw `please use " instead of ',example opc '(1 2)' -> opc "(1 2)"`

	isPrint &&	INFO(`> ${cmd}`)

	try{

		const result = execSync(cmd).toString();

		isPrint && INFO(`~ ${result}`)

		return result.replace(/[\r\n]/g,"");

	}catch(e){
		throw `调用失败:${e.stdout.toString()}`
	}


}


/**
	@Desc 运行系统命令 异步返回信息
	@Param cmd:String 命令字符串 
	@Param args:[String] 参数数组
	@Param printFlag:String 设置自动打印输出 默认：打印
*/
const SHELL_ASYNC = async (cmd,args,isPrint=true) => {

	const print = msg => isPrint &&	INFO(msg.toString())

	print(`> ${cmd} ${args}`)

	const ls = spawn(cmd,args);

	return new Promise((resolve,reject)=>{

		let dataSum = "";

		ls.stdout.on('data', d => {
			print(d)
			dataSum+=d;
		});

		ls.stderr.on('data', print);

		ls.on('close', (code) => {
		  resolve(ls)
		});

	})

}

const XCH_RATE = 1000000000000;


//chia 1xch等于XCH_RATE mojo  实际都以mojo运行
const XCH_TO_MOJO = num => num * XCH_RATE;


//将mojo兑换成xch
const MOJO_TO_XCH = (numStr) => {
	const num = numStr/XCH_RATE;
	const m = num.toExponential().match(/\d(?:\.(\d*))?e([+-]\d+)/);
	return num.toFixed(Math.max(0, (m[1] || '').length - m[2]));
}


const RANDOM_STRING = e => {    
    e = e || 32;
    var t = "ABCDEFGHJKMNPQRSTWXYZabcdefhijkmnprstwxyz2345678",
    a = t.length,
    n = "";
    for (i = 0; i < e; i++) n += t.charAt(Math.floor(Math.random() * a));
    return n
}

//创建临时文件
const CREATE_TEMP_FILE = (fileName,content) => {
	const t = fileName.split(".")
	const realName = `${RANDOM_STRING(4)}_${t[0]}_runtime.${t[1]}`
	const tempFile = path.join(__DIRNAME,realName)
	TEMP_FILES.push(tempFile)
	fs.writeFileSync(tempFile,content,{encoding:"utf-8"})
	return {realName,tempFile};
}

const isInteger = obj => typeof obj === 'number' && obj%1 === 0
	
const isString = obj => typeof obj === 'string'

const isArray = Array.isArray;

const convertToStdHex = hexStr => hexStr.indexOf("0x") === 0 ? hexStr.substring(2,hexStr.length) : hexStr;

const CONVERT_OPC = data => isArray(data) ? 
			"( "+data.reduce((s,v)=> s+(isArray(v) ? CONVERT_OPC(v) : " "+v+" "),"") +" )":
			""+data;


const RUN_FN = cb => cb()

const OPC_CODE = {
	AGG_SIG_UNSAFE:49,
	AGG_SIG_ME:50,
	CREATE_COIN:51,
	RESERVE_FEE:52,
	CREATE_COIN_ANNOUNCEMENT:60,
	ASSERT_COIN_ANNOUNCEMENT:61,
	CREATE_PUZZLE_ANNOUNCEMENT:62,
	ASSERT_PUZZLE_ANNOUNCEMENT:63,
	ASSERT_MY_COIN_ID:70,
	ASSERT_MY_PARENT_ID:71,
	ASSERT_MY_PUZZLEHASH:72,
	ASSERT_MY_AMOUNT:73,
	ASSERT_SECONDS_RELATIVE:80,
	ASSERT_SECONDS_ABSOLUTE:81,
	ASSERT_HEIGHT_RELATIVE:82,
	ASSERT_HEIGHT_ABSOLUTE:83
}

Array.prototype.sum = function(){
	return this.reduce((s,v)=>s+=v,0);
}
